package tp.pr2;

/**
 * A container of items. It can be employed by any class that stores items. A
 * container cannot store two items with the same identifier
 * 
 * It provides methods to add new items, access them and remove them from the
 * container.
 */
public class ItemContainer {

	private Item[] container = null;
	private int SIZE = 10; // Size of the previous array in memory
	private int numItems; // Number of items stored in the container
	private int ini; // Used when searching, it stores the position where the
						// Item is at, or should be inserted

	private static final String LINE_SEPARATOR = System
			.getProperty("line.separator");

	/**
	 * Creates the empty container
	 */
	public ItemContainer() {
		container = new Item[SIZE];
		numItems = 0;
	}

	/**
	 * Returns the number of items contained
	 * 
	 * @return the number of items in the container
	 */
	public int numberOfItems() {
		return numItems;
	}

	/**
	 * Add an item to the container. The operation can fail, returning false
	 * 
	 * @param item
	 *            - The name of the item to be added.
	 * @return true if and only if the item is added, i.e., an item with the
	 *         same identifier does not exists in the container
	 */
	public boolean addItem(Item item) {
		if (!search(item.getId())) {
			if (numItems + 1 == SIZE) { // En caso de que al a�adir un nuevo
										// item se desborde el array
				expand();
			}
			// El item hay que insertarlo en la posicion dada por ini tras
			// realizar search(), por tanto desplazamos
			// los elementos que est�n a su derecha para hacer hueco.

			for (int i = numItems - 1; i >= ini; i--) {
				container[i + 1] = container[i];
			}
			container[ini] = item;

			numItems++;

			return true;
		} else
			return false;
	}

	/**
	 * Returns the item from the container according to the item name
	 * 
	 * @param id
	 *            - Item name
	 * @return Item with that name or null if the container does not store an
	 *         item with that name
	 */
	public Item getItem(java.lang.String id) {
		if (search(id))
			return container[ini];
		else
			return null;
	}

	/**
	 * Returns and deletes an item from the inventory. This operation can fail,
	 * returning null
	 * 
	 * @param id
	 *            - Name of the item
	 * @return An item if and only if the item identified by id exists in the
	 *         inventory. Otherwise it returns null
	 */
	public Item pickItem(java.lang.String id) {
		if (search(id)) {
			Item picked = container[ini];
			// We delete it by traslating the elements located to the right
			for (int i = ini; i < numItems; i++)
				container[i] = container[i + 1];
			numItems--;
			return picked;
		} else
			return null;
	}

	/**
	 * Generates a String with information about the items contained in the
	 * container. Note that the items must appear sorted but the item name.
	 */
	public java.lang.String toString() {
		String text = new String();
		for (int i = 0; i < numItems; i++) {
			text += "   " + container[i].getId() + LINE_SEPARATOR;
		}
		return text;
	}

	/**
	 * Implements a binary search
	 * 
	 * @param id
	 *            - the key to search
	 * @return true iff an Item exists in the container with the same id.
	 */
	private boolean search(java.lang.String id) {
		ini = 0;
		int fin = numItems - 1;
		while (ini <= fin) {
			int m = (ini + fin) / 2;
			if (container[m].getId().compareToIgnoreCase(id) == 0) {
				ini = m;
				return true;
			} else if (container[m].getId().compareToIgnoreCase(id) < 0)
				ini = m + 1;
			else
				fin = m - 1;
		}
		return false;
	}

	/**
	 * Allows to expand the container array in memory
	 */
	private void expand() {
		Item[] tmp = new Item[SIZE];
		for (int i = 0; i < numItems; i++) {
			tmp[i] = container[i];
		}
		SIZE = SIZE * 2;
		container = new Item[SIZE];
		for (int i = 0; i < numItems; i++) {
			container[i] = tmp[i];
		}

	}
}
